package cn.edu.sgu.www.mhxysy.service.equipment.impl;

import cn.edu.sgu.www.mhxysy.consts.CustomMessages;
import cn.edu.sgu.www.mhxysy.consts.IdentifierPrefixes;
import cn.edu.sgu.www.mhxysy.dto.equipment.EquipmentDTO;
import cn.edu.sgu.www.mhxysy.dto.equipment.EquipmentForgeDTO;
import cn.edu.sgu.www.mhxysy.entity.baoshi.Baoshi;
import cn.edu.sgu.www.mhxysy.entity.baoshi.EquipmentBaoshi;
import cn.edu.sgu.www.mhxysy.entity.equipment.*;
import cn.edu.sgu.www.mhxysy.entity.qiling.Qiling;
import cn.edu.sgu.www.mhxysy.entity.role.RoleAccount;
import cn.edu.sgu.www.mhxysy.enums.EquipmentAttributeTypes;
import cn.edu.sgu.www.mhxysy.enums.InlayStatus;
import cn.edu.sgu.www.mhxysy.enums.WearStatus;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.function.computer.score.impl.EquipmentScoreComputer;
import cn.edu.sgu.www.mhxysy.function.forger.equipment.EquipmentForger;
import cn.edu.sgu.www.mhxysy.mapper.baoshi.BaoshiMapper;
import cn.edu.sgu.www.mhxysy.mapper.baoshi.EquipmentBaoshiMapper;
import cn.edu.sgu.www.mhxysy.mapper.equipment.*;
import cn.edu.sgu.www.mhxysy.mapper.qiling.QilingMapper;
import cn.edu.sgu.www.mhxysy.mapper.role.RoleAccountMapper;
import cn.edu.sgu.www.mhxysy.pager.Pager;
import cn.edu.sgu.www.mhxysy.redis.RedisUtils;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.service.equipment.EquipmentService;
import cn.edu.sgu.www.mhxysy.util.CollectionUtils;
import cn.edu.sgu.www.mhxysy.util.MathUtils;
import cn.edu.sgu.www.mhxysy.util.ObjectUtils;
import cn.edu.sgu.www.mhxysy.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Service
public class EquipmentServiceImpl implements EquipmentService {

	private final RedisUtils redisUtils;
	private final BaoshiMapper baoshiMapper;
	private final QilingMapper qilingMapper;
	private final EquipmentForger equipmentForger;
	private final EquipmentMapper equipmentMapper;
	private final RoleAccountMapper roleAccountMapper;
	private final EquipmentTypeMapper equipmentTypeMapper;
	private final EquipmentBaoshiMapper equipmentBaoshiMapper;
	private final EquipmentTexiaoMapper equipmentTexiaoMapper;
	private final EquipmentScoreComputer equipmentScoreComputer;
	private final EquipmentCategoryMapper equipmentCategoryMapper;
	private final EquipmentAttributeMapper equipmentAttributeMapper;
	private final EquipmentViewAttributeMapper equipmentViewAttributeMapper;

	@Autowired
	public EquipmentServiceImpl(
			RedisUtils redisUtils,
			BaoshiMapper baoshiMapper,
			QilingMapper qilingMapper,
			EquipmentForger equipmentForger,
			EquipmentMapper equipmentMapper,
			RoleAccountMapper roleAccountMapper,
			EquipmentTypeMapper equipmentTypeMapper,
			EquipmentBaoshiMapper equipmentBaoshiMapper,
			EquipmentTexiaoMapper equipmentTexiaoMapper,
			EquipmentScoreComputer equipmentScoreComputer,
			EquipmentCategoryMapper equipmentCategoryMapper,
			EquipmentAttributeMapper equipmentAttributeMapper,
			EquipmentViewAttributeMapper equipmentViewAttributeMapper) {
		this.redisUtils = redisUtils;
		this.baoshiMapper = baoshiMapper;
		this.qilingMapper = qilingMapper;
		this.equipmentForger = equipmentForger;
		this.equipmentMapper = equipmentMapper;
		this.roleAccountMapper = roleAccountMapper;
		this.equipmentTypeMapper = equipmentTypeMapper;
		this.equipmentBaoshiMapper = equipmentBaoshiMapper;
		this.equipmentTexiaoMapper = equipmentTexiaoMapper;
		this.equipmentScoreComputer = equipmentScoreComputer;
		this.equipmentCategoryMapper = equipmentCategoryMapper;
		this.equipmentAttributeMapper = equipmentAttributeMapper;
		this.equipmentViewAttributeMapper = equipmentViewAttributeMapper;
	}

	@Override
	public void compute(String equipmentId) {
		UpdateWrapper<Equipment> updateWrapper = new UpdateWrapper<>();

		updateWrapper.eq("id", equipmentId);
		updateWrapper.set("score", equipmentScoreComputer.compute(equipmentId));

		equipmentMapper.update(updateWrapper.getEntity(), updateWrapper);
	}

	@Override
	public void forge(EquipmentForgeDTO equipmentForgeDTO) {
		equipmentForger.forge(equipmentForgeDTO);
	}

	@Override
	public void insert(EquipmentDTO equipmentDTO) {
		// 检查角色和装备的等级
		if (WearStatus.YCD.getValue().equals(equipmentDTO.getWearStatus())) {
			checkGrade(equipmentDTO);
		}

		// 查询装备类型信息
		Integer categoryId = equipmentDTO.getCategoryId();

		EquipmentCategory equipmentCategory = equipmentCategoryMapper.selectById(equipmentDTO.getCategoryId());

		/*
		 * 1、添加装备
		 */
		Equipment equipment = toEntity(equipmentDTO);

		if (equipmentCategory.getGrade() < 90) {
			equipment.setFulingStatus(0);
		}

		if (equipment.getScore() == null) {
			equipment.setScore(0);
		}

		equipment.setId(equipment.uuid());

		equipmentMapper.insert(equipment);

		/*
		 * 2、添加装备属性
		 */
		Integer topType = equipmentTypeMapper.selectTopType(categoryId);

		// 查询装备预览属性
		QueryWrapper<EquipmentViewAttribute> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("grade", equipmentCategory.getGrade());
		queryWrapper.eq("equipment_id", topType);
		queryWrapper.eq("forge_type", equipmentDTO.getForgeType());

		List<EquipmentViewAttribute> list = equipmentViewAttributeMapper.selectList(queryWrapper);

		// 为装备添加[min, max]随机的默认属性值
		if (CollectionUtils.isNotEmpty(list)) {
			for(EquipmentViewAttribute viewAttribute : list) {
				EquipmentAttribute attribute = new EquipmentAttribute();
				// 得到装备预览属性的属性id
				Integer propertyId = viewAttribute.getPropertyId();
				// 生成[min, max]的随机值
				int random = MathUtils.random(viewAttribute.getMin(), viewAttribute.getMax());

				// 设置装备属性信息
				attribute.setId(IdentifierPrefixes.PREFIX_ZBSX + redisUtils.uuid());
				attribute.setType(EquipmentAttributeTypes.PUTONG.getValue()); // 普通属性
				attribute.setEquipmentId(equipment.getId());
				attribute.setPropertyId(propertyId);
				attribute.setPropertyValue(random);

				// 为装备添加属性
				equipmentAttributeMapper.insert(attribute);
			}
		}
	}

	@Override
	public void deleteByIds(List<String> ids) {
		if (CollectionUtils.isNotEmpty(ids)) {
			// 1、删除装备属性
			QueryWrapper<EquipmentAttribute> queryWrapper = new QueryWrapper<>();

			queryWrapper.in("equipment_id", ids);

			equipmentAttributeMapper.delete(queryWrapper);

			// 2、批量修改宝石信息
			QueryWrapper<EquipmentBaoshi> queryWrapper1 = new QueryWrapper<>();

			queryWrapper1.in("equipment_id", ids);

			List<EquipmentBaoshi> list = equipmentBaoshiMapper.selectList(queryWrapper1);

			if (CollectionUtils.isNotEmpty(list)) {
				// 2.1 删除装备宝石
				equipmentBaoshiMapper.delete(queryWrapper1);

				Stream<EquipmentBaoshi> stream = list.stream();
				// 得到宝石ID列表
				List<String> baoshiIds = stream.map(new Function<EquipmentBaoshi, String>() {
					@Override
					public String apply(EquipmentBaoshi equipmentBaoshi) {
						return equipmentBaoshi.getBaoshiId();
					}
				}).collect(Collectors.toList());

				// 2.2 批量修改宝石的镶嵌状态
				UpdateWrapper<Baoshi> updateWrapper = new UpdateWrapper<>();

				updateWrapper.in("id", baoshiIds);
				updateWrapper.eq("inlay_status", InlayStatus.YXQ.getValue());

				updateWrapper.set("inlay_status", InlayStatus.WXQ.getValue());

				baoshiMapper.update(updateWrapper.getEntity(), updateWrapper);
			}

			// 3、批量修改器灵镶嵌状态
			UpdateWrapper<Qiling> updateWrapper = new UpdateWrapper<>();

			updateWrapper.in("equipment_id", ids);
			updateWrapper.eq("inlay_status", InlayStatus.YXQ.getValue());

			updateWrapper.set("equipment_id", null);
			updateWrapper.set("inlay_status", InlayStatus.WXQ.getValue());

			qilingMapper.update(updateWrapper.getEntity(), updateWrapper);

			// 4、批量删除装备
			equipmentMapper.deleteBatchIds(ids);
		}
	}

	@Override
	public void updateById(EquipmentDTO equipmentDTO) {
		ObjectUtils.requireNonNull(equipmentDTO.getId(), CustomMessages.ID_NOT_NULL);

		if (WearStatus.YCD.getValue().equals(equipmentDTO.getWearStatus())) {
			checkGrade(equipmentDTO); // 检查角色和装备的等级
		}

		// 等级不到90的装备强制设置附灵状态为0-未附灵
		Integer categoryId = equipmentDTO.getCategoryId();
		EquipmentCategory equipmentCategory = equipmentCategoryMapper.selectById(categoryId);

		// 修改装备信息
		Equipment equipment = toEntity(equipmentDTO);

		if (equipmentCategory.getGrade() < 90) {
			equipment.setFulingStatus(0);
		}

		equipmentMapper.updateById(equipment);
	}

	@Override
	public List<Equipment> selectAll() {
		return equipmentMapper.selectList(null);
	}

	@Override
	public Equipment selectById(String id) {
		return equipmentMapper.selectById(id);
	}

	@Override
	public int getTotalScore(String equipmentId) {
		AtomicInteger score = new AtomicInteger();

		// 计算装备评分
		Integer apply = equipmentScoreComputer.compute(equipmentId);

		score.addAndGet(apply);

		// 查询装备镶嵌的宝石
		Map<String, Object> columnMap = new HashMap<>();

		columnMap.put("equipment_id", equipmentId);

		List<EquipmentBaoshi> list = equipmentBaoshiMapper.selectByMap(columnMap);

		if (CollectionUtils.isNotEmpty(list)) {
			// 从装备宝石列表中获取宝石ID
			Stream<EquipmentBaoshi> stream = list.stream();
			List<String> baoshiIds = stream.map(new Function<EquipmentBaoshi, String>() {
				@Override
				public String apply(EquipmentBaoshi equipmentBaoshi) {
					return equipmentBaoshi.getBaoshiId();
				}
			}).collect(Collectors.toList());

			// 查询宝石信息
			QueryWrapper<Baoshi> queryWrapper = new QueryWrapper<>();

			queryWrapper.in("id", baoshiIds);
			queryWrapper.eq("inlay_status", InlayStatus.YXQ.getValue());

			List<Baoshi> baoshiList = baoshiMapper.selectList(queryWrapper);

			// 添加宝石的评分：宝石等级 × 12
			if (CollectionUtils.isNotEmpty(baoshiList)) {
				for (Baoshi baoshi : baoshiList) {
					score.addAndGet(baoshi.getGrade() * 12);
				}
			}
		}

		// 查询装备镶嵌的器灵
		QueryWrapper<Qiling> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("equipment_id", equipmentId);
		queryWrapper.eq("inlay_status", InlayStatus.YXQ.getValue());

		Qiling qiling = qilingMapper.selectOne(queryWrapper);

		if (qiling != null) {
			score.addAndGet(qiling.getScore());
		}

		return score.get();
	}

	@Override
	public List<Equipment> selectByRoleId(String roleId) {
		QueryWrapper<Equipment> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq(
				StringUtils.isNotEmpty(roleId),
				"role_id", roleId
		);

		return equipmentMapper.selectList(queryWrapper);
	}

	@Override
	public Page<Equipment> selectByPage(Pager<Equipment> pager) {
		QueryWrapper<Equipment> queryWrapper = Pager.getQueryWrapper(pager, false);
		Page<Equipment> page = Pager.ofPage(pager);

		// 得到order by语句
		String statement = Pager.getOrderByStatement(pager);

		if (StringUtils.isNotEmpty(statement)) {
			queryWrapper.last(statement);
		}

		return equipmentMapper.selectPage(page, queryWrapper);
	}

	@Override
	public List<Equipment> selectByCategoryId(Integer categoryId) {
		QueryWrapper<Equipment> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq(
				categoryId != null,
				"category_id", categoryId
		);

		return equipmentMapper.selectList(queryWrapper);
	}

	private Equipment toEntity(EquipmentDTO equipmentDTO) {
		Equipment equipment = new Equipment();

		equipment.setId(equipmentDTO.getId());
		equipment.setScore(equipmentDTO.getScore());
		equipment.setForger(equipmentDTO.getForger());
		equipment.setRoleId(equipmentDTO.getRoleId());
		equipment.setTejiId(equipmentDTO.getTejiId());
		equipment.setTexiaoId(equipmentDTO.getTexiaoId());
		equipment.setFailTimes(equipmentDTO.getFailTimes());
		equipment.setForgeType(equipmentDTO.getForgeType());
		equipment.setCategoryId(equipmentDTO.getCategoryId());
		equipment.setDurability(equipmentDTO.getDurability());
		equipment.setWearStatus(equipmentDTO.getWearStatus());
		equipment.setFulingStatus(equipmentDTO.getFulingStatus());

		return equipment;
	}

	/**
	 * 检查角色等级和装备等级
	 * @param equipmentDTO 装备信息
	 */
	private void checkGrade(EquipmentDTO equipmentDTO) {
		String roleId = equipmentDTO.getRoleId();
		Integer categoryId = equipmentDTO.getCategoryId();

		// 检查装备等级和角色等级
		if (StringUtils.isNotEmpty(roleId) && WearStatus.YCD.getValue().equals(equipmentDTO.getWearStatus())) {
			// 查询装备类型信息
			EquipmentCategory equipmentCategory = equipmentCategoryMapper.selectById(categoryId);
			// 查询角色账号信息
			RoleAccount roleAccount = roleAccountMapper.selectById(roleId);

			// 获取角色等级和装备等级
			Integer equipmentGrade = equipmentCategory.getGrade();
			Integer roleGrade = roleAccount.getGrade();

			// 角色等级低于装备等级
			if (roleGrade < equipmentGrade) {
				Integer texiaoId = equipmentDTO.getTexiaoId();

				// 装备存在特效，检查特效是否为【简易】
				if (texiaoId != null && texiaoId > 0) {
					EquipmentTexiao texiao = equipmentTexiaoMapper.selectById(texiaoId);

					// 特效是简易，检查是否符合条件：角色等级 + 5 >= 装备等级
					if ("简易".equals(texiao.getName())) {
						int result = roleGrade + 5 - equipmentGrade;

						if (result < 0) {
							throw new GlobalException(ResponseCode.FORBIDDEN, "装备等级太高了，无法穿戴");
						}
					} else { // 特效不是简易
						throw new GlobalException(ResponseCode.FORBIDDEN, "装备等级太高了，无法穿戴");
					}
				} else { // 装备没有特效
					throw new GlobalException(ResponseCode.FORBIDDEN, "装备等级太高了，无法穿戴");
				}
			}
		}

	}

}